#pragma once

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <signal.h>
#include "Log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"
#include "Daemon.hpp"

const int defaultfd = -1;
const std::string defaultip = "0.0.0.0";
const int backlog = 10;// 一般不要设置太大

enum 
{
    UsageError = 1,
    SocketError,
    BindError,
    ListenError
};

class TcpServer;

// // 多线程版本
// class ThreadData
// {
// public:
//     ThreadData(int fd, const std::string &ip, const uint16_t &port, TcpServer *tsvr)
//     :sockfd_(fd), clientip_(ip), clientport_(port), tsvr_(tsvr)
//     {}
// public:
//     int sockfd_;
//     std::string clientip_;
//     uint16_t clientport_;
//     TcpServer *tsvr_;
// };

class TcpServer
{
public:
    TcpServer(const uint16_t &port, const std::string &ip = defaultip)
    :listensock_(defaultfd), port_(port), ip_(ip)
    {
    }
    ~TcpServer()
    {}
    void InitServer()
    {
        listensock_ = socket(AF_INET, SOCK_STREAM, 0);
        if(listensock_ < 0)
        {
            lg(Fatal, "create socket, errno: %d, errstring: %s", errno, strerror(errno));
            exit(SocketError);
        }
        lg(Info, "create socket success, listensock_: %d", listensock_);

        int opt = 1;
        // 防止偶发性的服务器无法进行立即重启（tcp协议会详细讲述）
        setsockopt(listensock_, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt));

        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        inet_aton(ip_.c_str(), &(local.sin_addr));
        //local.sin_addr.s_addr = INADDR_ANY;

        if(bind(listensock_, (sockaddr *)(&local), sizeof(local)) < 0)
        {
            lg(Fatal, "bind error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(BindError);
        }

        lg(Info, "bind socket success, listensock_: %d", listensock_);

        // TCP是面向连接的，服务器一般是比较“被动的”，服务器一直处于一种状态，一直在等待连接到来的状态
        if(listen(listensock_, backlog) < 0)
        {
            lg(Fatal, "listen error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(ListenError);
        }
        lg(Info, "listen socket success, listensock_: %d", listensock_);

    }
    void Start()
    {
        Daemon();
        ThreadPool<Task> *tp = ThreadPool<Task>::GetInstance();
        tp->Start();
        lg(Info, "Tcp Server is running...");

        for(;;)
        {
            // 1.获取新的连接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(listensock_, (struct sockaddr *)(&client), &len);
            if(sockfd < 0)
            {
                lg(Warning, "accept error, errno: %d, errstring: %s", errno, strerror(errno));
                continue;
            }

            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &client.sin_addr, clientip, sizeof(client));

            // 2.根据新连接来通信
            lg(Info, "get a new link..., sockfd: %d, client ip: %s, clientport: %d", sockfd, clientip, clientport);

            // version4： ThreadPool
            Task t(sockfd, clientip, clientport);
            tp->Push(t); // 主线程只要将任务 push进 threadpool即可，threadpool内部会处理任务
        }
    }
private:
    int listensock_;
    uint16_t port_;
    std::string ip_;
};